
/*本文件主要实现了从备份信息文件读取备份信息,及管理文件备份信息*/

#ifndef __DATA_HPP__
#define __DATA_HPP__

#include <string>
#include <unordered_map>
#include "util.hpp"
#include "config.hpp"
#include "sqlUtil.hpp"
#include "backUPInfo.hpp"
#include "redisUtil.hpp"

namespace cloud
{
    class DataManager // 主要负责
    {
    private:
        pthread_rwlock_t _rwlock;                           // 读写锁
        std::unordered_map<std::string, BackupInfo> _table; // url--文件信息
        static std::mutex _mutex;
        static DataManager *_instance;

    private:
        DataManager()
        {
            pthread_rwlock_init(&_rwlock, nullptr);
            InitLoad();
        }

        bool InitLoad() // 初始化程序运行时从文件读取数据
        {
            std::vector<string> filename;
            std::vector<size_t> filesize;
            std::vector<string> time;

            // 初次加载从数据库获取文件信息
            SqlManager::GetInstance()->GetAllFileInfo(filename, filesize, time);

            for (int i = 0; i < filename.size(); i++)
            {
                // 读取文件信息到哈希表
                BackupInfo tmp;
                tmp._filename = filename[i];
                tmp._fsize = filesize[i];
                tmp._time = time[i];
                // 下载前缀加文件名构成URL,如download/test.txt
                tmp._url = Config::GetInstance()->GetDownloadPrefix() + filename[i];
                _table[tmp._url]=tmp;

                
            }
            Log::getLogger("globalLogger")->_info("数据库获取文件信息成功!!!");
            return true;
        }

    public:
        ~DataManager()
        {
            pthread_rwlock_destroy(&_rwlock); // 销毁读写锁
        }

        static DataManager *GetInstance()
        {
            if (_instance == nullptr)
            {
                _mutex.lock();
                if (_instance == nullptr)
                {
                    _instance = new DataManager();
                }
                _mutex.unlock();
            }
            return _instance;
        }

        void Storage(const BackupInfo &val)
        {
            //先压缩再加载进数据库
            FileUtil pack(val._real_path);
            std::string packed;//获取压缩内容缓存进redis
            pack.Compress(val._pack_path,&packed);
            pack.Remove();//压缩后移除原文件
            //mysql存储
            SqlManager::GetInstance()->InsertContent(val);
            SqlManager::GetInstance()->InsertFile(val._filename,val._md5,val._fsize);
            //redis缓存
            RedisUtil::GetInstance()->Set(val._filename,val._md5);
            RedisUtil::GetInstance()->Set(val._md5,packed);

            FileUtil(val._pack_path).Remove();//移除压缩文件
        }

        void Insert(const BackupInfo &val) // 每次新上传文件,其信息需要插入哈希表,并持久化存储到文件
        {
            pthread_rwlock_wrlock(&_rwlock); // 加写锁
            _table[val._url] = val;
            pthread_rwlock_unlock(&_rwlock);
            Storage(val);
        }

        void Update(const BackupInfo &val)
        {
            return Insert(val);
        }

        bool GetOneByURL(const std::string &url, BackupInfo *info)
        {
            pthread_rwlock_rdlock(&_rwlock); // 加写锁,预防在读的时候修改哈希表导致哈希表扩容等导致的不可预测后果
            if (_table.count(url) == 0)
            {
                pthread_rwlock_unlock(&_rwlock);
                return false;
            }
            *info = _table[url];
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }

        bool GetOneByRealPath(const std::string &realpath, BackupInfo *info)
        {
            pthread_rwlock_rdlock(&_rwlock); // 加写锁,预防在读的时候修改哈希表导致哈希表扩容等导致的不可预测后果
            BackupInfo tmp;
            tmp.initByRealPath(realpath);
            if (_table.count(realpath) == 0)
            {
                pthread_rwlock_unlock(&_rwlock);
                return false;
            }
            *info = _table[tmp._url];
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }

        void GetAll(std::vector<BackupInfo> *arry)
        {
            pthread_rwlock_wrlock(&_rwlock); // 加写锁,预防在读的时候修改哈希表导致哈希表扩容等导致的不可预测后果
            for (auto &x : _table)
            {
                arry->push_back(x.second);
            }
            pthread_rwlock_unlock(&_rwlock);
        }
    };
    std::mutex DataManager::_mutex;
    DataManager *DataManager::_instance = nullptr;

}; // namespace cloud

#endif //__DATA_HPP__